import { Injectable, NotFoundException } from '@nestjs/common';
import { CreateMenuDto } from './dto/create-menu.dto';
import { UpdateMenuDto } from './dto/update-menu.dto';
import { SysMenu } from 'src/entities/sys-menu.entity';
import { Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { RouteConfig } from './vo/route-config.vo';
import { SysRole } from 'src/entities/sys-role.entity';
import { SysUser } from 'src/entities/sys-user.entity';

interface TreeMenu {
  value: string;
  label: string;
  children?: TreeMenu[];
}

@Injectable()
export class MenuService {
  constructor(
    @InjectRepository(SysMenu)
    private menuRepository: Repository<SysMenu>,
    @InjectRepository(SysRole)
    private roleRepository: Repository<SysRole>,
  ) {}
  async create(createMenuDto: CreateMenuDto): Promise<any> {
    const menu = new SysMenu();

    // 显式映射属性，避免重复和命名冲突
    menu.name = createMenuDto.name;
    menu.parent_id = createMenuDto.parent_id || 0;
    menu.icon = createMenuDto.icon;
    menu.route_path = createMenuDto.route_path;
    menu.component = createMenuDto.component;
    menu.redirect = createMenuDto.redirect;
    menu.route_name = createMenuDto.route_name;
    menu.visible =
      createMenuDto.visible === undefined ? true : createMenuDto.visible;
    menu.sort = createMenuDto.sort || 1;
    menu.type = createMenuDto.type;
    menu.always_show = createMenuDto.always_show || 0;
    menu.keep_alive = createMenuDto.keep_alive || 1;

    if (createMenuDto.type === 2) {
      menu.component = 'Layout';
    }
    if (createMenuDto.type === 4) {
      menu.perm = createMenuDto.perm;
    }
    try {
      await this.menuRepository.save(menu);
    } catch (error) {
      console.log(error.message);
      throw new Error('Menu already exists');
    }
    return {
      message: 'success',
    };
  }

  async update(id: number, updateMenuDto: UpdateMenuDto): Promise<SysMenu> {
    const menu = await this.menuRepository.findOne({ where: { id } });
    if (!menu) {
      throw new Error('Menu not found');
    }

    Object.assign(menu, updateMenuDto);
    return this.menuRepository.save(menu);
  }

  async findAll() {
    return this.menuRepository.find({
      order: {
        sort: 'ASC',
      },
    });
  }

  async findOne(id: number): Promise<SysMenu> {
    const menu = await this.menuRepository.findOne({ where: { id } });
    if (!menu) {
      throw new NotFoundException(`菜单ID为${id}的数据不存在`);
    }
    return menu;
  }

  async remove(id: number): Promise<void> {
    await this.menuRepository.delete(id);
  }

  async getMenuTree() {
    const menus = await this.findAll();
    return this.buildTree(menus);
  }

  private buildTree(menus: SysMenu[], parentId: number = 0) {
    const tree = [];
    for (const menu of menus) {
      if (Number(menu.parent_id) === parentId) {
        const children = this.buildTree(menus, Number(menu.id));
        if (children.length) {
          menu['children'] = children;
        }
        tree.push(menu);
      }
    }
    return tree;
  }

  async getMenuTreeAssignPer(
    filterButtons: boolean = false,
  ): Promise<TreeMenu[]> {
    // 获取所有菜单
    const menus = await this.findAll();

    // 如果需要过滤按钮，获取所有非按钮类型的菜单
    const filteredMenus = filterButtons
      ? menus.filter((menu) => menu.type !== 4) // 假设类型4是按钮类型
      : menus;

    // 构建树形结构
    const buildTree = (parentId: number | null): TreeMenu[] => {
      const children = filteredMenus
        .filter((menu) => Number(menu.parent_id) === parentId)
        .map((menu) => {
          const node: TreeMenu = {
            value: menu.id.toString(),
            label: menu.name,
          };

          const childNodes = buildTree(Number(menu.id));
          if (childNodes.length) {
            node.children = childNodes;
          }

          return node;
        });

      return children;
    };

    // 从顶级菜单开始构建
    return buildTree(0);
  }

  async getRouteConfig(userId: number): Promise<RouteConfig[]> {
    let menus = await this.findAll();

    // 如果提供了用户ID，获取该用户所有角色的菜单权限并集
    if (userId) {
      // 获取用户的角色IDs
      const roleIds = await this.getUserRoleIds(userId);
      if (roleIds && roleIds.length > 0) {
        // 获取所有角色对应的菜单ID并集
        const roleMenuIds = await this.getRoleMenuIds(roleIds);
        // 过滤菜单，只保留用户角色有权限的菜单
        menus = menus.filter((menu) => roleMenuIds.includes(Number(menu.id)));
      } else {
        // 用户没有角色，返回空路由
        return [];
      }
    }

    const buildRoutes = (parentId: number = 0): RouteConfig[] => {
      return menus
        .filter((menu) => Number(menu.parent_id) === parentId)
        .map((menu) => {
          const route: RouteConfig = {
            path: menu.route_path || '',
            component: menu.component || '',
            name: menu.route_name || '',
            meta: {
              title: menu.name,
              icon: menu.icon || '',
              hidden: !menu.visible,
              keepAlive: menu.keep_alive === 1,
              alwaysShow: menu.always_show === 1,
              params: menu.params,
            },
          };

          if (menu.redirect) {
            route.redirect = menu.redirect;
          }

          const children = buildRoutes(Number(menu.id));
          if (children.length) {
            route.children = children;
          }

          return route;
        })
        .filter((route) => route.path); // 过滤掉没有路径的菜单
    };

    return buildRoutes();
  }

  // 获取用户角色IDs
  async getUserRoleIds(userId: number): Promise<number[]> {
    try {
      // 从数据库中查询用户实体并加载关联的角色
      const userWithRoles = await this.menuRepository.manager.findOne(SysUser, {
        where: { id: userId },
        relations: ['roles'],
      });

      if (!userWithRoles || !userWithRoles.roles) {
        return [];
      }

      // 提取角色IDs
      return userWithRoles.roles.map((role) => role.id);
    } catch (error) {
      console.error('获取用户角色失败:', error);
      return [];
    }
  }

  // 获取角色菜单IDs
  private async getRoleMenuIds(roleIds: number[]): Promise<number[]> {
    // 查询多个角色对应的菜单IDs
    const roleIdStr = roleIds.join(',');
    const query = `
    SELECT DISTINCT menu_id FROM sys_role_menu 
    WHERE role_id IN (${roleIdStr})
  `;

    try {
      // 添加类型断言或接口定义
      interface RoleMenu {
        menu_id: string | number;
      }
      const roleMenus = (await this.menuRepository.query(query)) as RoleMenu[];
      return [...new Set(roleMenus.map((item) => Number(item.menu_id)))]; // 使用Set去重
    } catch (error) {
      console.error('获取角色菜单失败:', error);
      return [];
    }
  }
}
